/**
 * @description 音效管理
 * @date 2024.9.10
 * @author wz
 * @midify 2025.3.13
 * @editor wz
 */
import { _decorator, Component, Node, AudioSource, AudioClip, tween, Tween, math, sys } from 'cc';
import { Singleton } from '../../utils/Singleton';
import { resMgr } from '../res/ResMgr';
import { director } from 'cc';
import { AudioItem } from './AudioItem';

const { ccclass, property } = _decorator;



@ccclass('AudioMgr')
export class AudioMgr extends Singleton {

    private readonly _water = 20;
    private readonly _defaultMusicVolum = 0.5;
    private readonly _defaultSoundVolum = 0.5;

    private _canvas: Node = null;
    get canvas(): Node {
        if (!this._canvas)
            this._canvas = director.getScene()?.getChildByName('Canvas')
        return this._canvas;
    }

    /**
     * 背景音量
     */
    private _musicVolume = 0;
    set musicVolume(value) {
        if (this._musicAudioSource) {
            this._musicVolume = math.clamp01(value)
            this._musicAudioSource.getComponent(AudioSource).volume = this._musicVolume;
        }
    }
    get musicVolume() {
        return this._musicVolume;
    }

    /**
     * 音效音量
     */
    private _soundVolume = 0;
    set soundVolume(value) {
        this._soundVolume = math.clamp01(value)
        this._soundAudioItems.forEach((a) => a.setVolume(this._soundVolume))
    }
    get soundVolume() {
        return this._soundVolume;
    }

    /**
     * 背景音乐播放器
     */
    private _musicAudioSource: AudioSource = null;
    get musicAudioSource() {
        if (!this._musicAudioSource) {
            let node = new Node('musicAudioItem')
            this.canvas.addChild(node);
            this._musicAudioSource = node.addComponent(AudioSource);
        }
        return this._musicAudioSource
    }

    /**
     * 音效播放器
     */
    private _soundAudioItems: AudioItem[] = [];
    /**
     * 音效资源
     */
    private _audioClips: AudioClip[] = [];

    constructor() {
        super();
        const cacheMusicVolum = sys.localStorage.getItem("musicVolume")
        this._musicVolume = !!cacheMusicVolum ? parseFloat(cacheMusicVolum) : this._defaultMusicVolum;
        const cacheSoundVolum = sys.localStorage.getItem("soundVolume")
        this._soundVolume = !!cacheSoundVolum ? parseFloat(cacheSoundVolum) : this._defaultSoundVolum;
    }

    /**
     * 检查是否释放
     */
    private _checkWater() {
        const canReleases = this._audioClips.filter(a => a.refCount <= 0);
        const count = canReleases.length - this._water
        if (count > 0) {
            for (let i = 0; i < count; i++) {
                const clip = canReleases[i];
                clip.decRef(true);
                this._audioClips.splice(this._audioClips.indexOf(clip), 1);
            }
        }
    }

    /**
     * 获取音效播放item
     * @returns 
     */
    private _getItem() {
        let audioItem = this._soundAudioItems.find(a => !a.isPlay)
        if (!audioItem) {
            if (this._soundAudioItems.length < AudioSource.maxAudioChannel - 1) {
                let node = new Node('soundAudioItem')
                this.canvas.addChild(node);
                node.addComponent(AudioSource);
                audioItem = node.addComponent(AudioItem);
                audioItem.isPlay = false;
                this._soundAudioItems.push(audioItem)
            }
            else {
                let index = 0, timeStamp = new Date().getTime();
                for (let i = 0; i < this._soundAudioItems.length; i++) {
                    if (this._soundAudioItems[i].startPlayTimmstamp < timeStamp) {
                        index = i;
                        timeStamp = this._soundAudioItems[index].startPlayTimmstamp;
                    }
                }
                audioItem = this._soundAudioItems[index];
                audioItem.stop();
            }
        }
        return audioItem;
    }


    /**
     * 播放音效
     * @param audio 
     * @param times 
     */
    playSound(path: string, bundleName: string = 'resources', times: number = 1) {
        this._checkWater();
        times = times < 1 ? 1 : times;
        let audioItem = this._getItem();
        audioItem.isPlay = true;
        audioItem.startPlayTimmstamp = new Date().getTime();
        resMgr.load(path, AudioClip, bundleName)
            .then((clip: AudioClip) => {
                if (this._audioClips.indexOf(clip) == -1)
                    this._audioClips.push(clip);
                audioItem.play(clip, times, this.soundVolume)
            })
            .catch(() => {
                audioItem.isPlay = false;
            })
    }

    /**
     * 播放背景音乐
     */
    private _playMusic(audioSource: AudioSource, clip: AudioClip, loop: boolean, volume: number) {
        if (audioSource.clip) {
            audioSource.stop();
            //不释放，只减少计数
            audioSource.clip.decRef(false);
            audioSource.clip = null;
        }
        audioSource.clip = clip;
        audioSource.clip.addRef();
        audioSource.loop = loop;
        audioSource.volume = volume;
        audioSource.play();
    }

    /**
     * 播放背景音乐
     */
    playMusic(path: string, bundleName: string = 'resources') {
        this._checkWater();
        resMgr.load(path, AudioClip, bundleName)
            .then((clip: AudioClip) => {
                if (this._audioClips.indexOf(clip) == -1)
                    this._audioClips.push(clip);
                this._playMusic(this.musicAudioSource, clip, true, this.musicVolume)
            })
    }


    /**
     * 停止播放背景音乐
     */
    stopMusic() {
        if (this._musicAudioSource) {
            this._musicAudioSource.stop();
            this._musicAudioSource.clip = null;
        }
    }

    /**
     * 暂停播放背景音乐
     */
    pauseMusic() {
        if (this._musicAudioSource)
            this._musicAudioSource.pause();
    }

    /**
     * 恢复背景音乐播放
     */
    resumeMusic() {
        if (this._musicAudioSource)
            this._musicAudioSource.play();
    }

    /**
     * 停止播放音效
     */
    stopSound() {
        this._soundAudioItems.forEach(a => a.stop())
    }

    /**
     * 保存音量大小
     * @param musicVolume 
     * @param soundVolume 
     */
    saveVolume(musicVolume: number, soundVolume) {
        this.musicVolume = musicVolume;
        this.soundVolume = soundVolume;
        sys.localStorage.setItem("musicVolume", this.musicVolume + '');
        sys.localStorage.setItem("soundVolume", this.soundVolume + '');
    }
}
/**
 * 音效管理
 */
export const audioMgr: AudioMgr = AudioMgr.getInstance<AudioMgr>()